When using the COMPILE statement in a program with the _caseInsensitive parameter, you must ensure that any INCLUDE files called by the main program have an identical statement. Ignoring this can cause all kinds of problems.
When _caseInsensitive is used, FutureBASIC compares all variables AND function names in uppercase letters, if the INCLUDE file does not have this parameter set, the compiler can't match FN THIS (main program) with FN This (INCLUDE file).
Most simply, if you use a COMPILE settings in the main program, use the same one in all INCLUDE files used by the program.
When a user selects Help from the Apple menu its possible they will get an alert that displays a "Help file still under construction" message. This is somewhat misleading since the default help file is probably available but the Help tool isn't.
The problem is that the Help tool has inadvertantly been "turned off" or not enabled to autostart when FutureBASIC is opened. To re-enable the Help tool, use the Tool Manager under the Tools menu to view the current set of tools. Select the Help tool, then enable the Autostart button. This places a black diamond in front of the Help tool showing you it autostart is set for that tool.
When you close the Tool Manager, all tools set to autostart are re-initialized into memory.
The introduction of LOCAL FN was heralded as a boon to programmers being overrun with out-of-control global variables. This jubilation was justified, but, incorrect usage of LOCAL FNs can lead to a shortage of stack space in the program. This in turn can cause text in dialogs, menus, windows to not display, as well as system errors. Not something we are looking for in a well-behaved program.
A LOCAL FN takes the parameters passed to it and places them on the stack. Any variables dimensioned inside the LOCAL FN are also created on the stack. The stack space allocated to a particular machine varies but in many instances will be around 8K-32K. If the size of the remaining stack is less than the LOCAL FN requires, a stack overflow can result, munging other code in memory
The following example demonstrates the problem:
LOCAL FN TestStack
DIM 255 test$ (49)
' do something with these strings
END FN
If we imagine we had a normal 8K stack, this simple DIM statement overflows the stack immediately (256 bytes * 50 strings = 12800 bytes, or about 4K more than the stack can handle. The first symptoms of stack shortages will be evident when text that once appeared just fine now fails to appear in file dialogs, windows, and in extreme cases, menus. Let's state one truism now:
YOU CAN NOT USE LOCAL FNs LIKE YOU WOULD GOTO!
In other words, you cannot call FN after FN regardless of where they appear in the program just as you once did with GOTO. GOTO allows a one way jump to any point in a program. Unlike GOTO, each call to a LOCAL FN places a return address on the stack causing it to grow. With enough FN calls that DON'T RETURN to the originating point, its possible to execeed the original 8k of stack space very rapidly.
Instead, a LOCAL FN must be considered like a GOSUB statement. A GOSUB jumps to any point in a program, BUT, it places a return address on the stack that allows program control to jump back to its previous position when a RETURN is encountered.
The best example of performing calls to LOCAL FNs correctly are shown in the example programs included on the Examples disk.
You can determine the amount of stack space available and reset it using the following routine:
"IncreaseStackSpace"
LONG IF [_applLimit] - [_heapEnd] < maxHeapSize&
& [_applLimit], [_heapEnd] + maxHeapSize&
END IF
This routine should only be called ONCE in the program before executing any other initialization routines.
FutureBASIC's built-in assembler currently has a few limitations and, well, how shall we put it, "unexpected features"? If you use the built-in assembler, you will probably want to be aware of the following problems:
1) Spaces must NOT be used between instruction operands. For example, the following statement will assemble incorrectly:
` move.l ^MyVar&, d0
but
` move.l ^MyVar&,d0
will assemble correctly.
2) The assembler will not currently accept the condition code register as an operand. Thus, the instruction
` move CCR,-(sp)
will cause the compiler to complain. Of course, you can always work around a problem like this by using the assembler's dc.w and dc.l directives. For instance, the above instruction could be assembled as follows:
_PushCCR = &42E7
` dc.w PushCCR
or:
_PushSR = &40E7
` dc.w PushSR
3) The assembler reverses the operands of an EOR instruction (although it makes no similar mistake with the Winnie the Pooh instruction). For example, if you really want to exclusive-or the d2 data register with the d0 data register, be sure to write
A definition error was discovered in the Toolbox with FN HANDANDHAND. As it stood, the function was missing a parameter and returned the incorrect result.
Fixing this Bug:
You can use ResEdit to correct this problem by modifying a word in a resource in the Future Extras file. The steps include:
1. Run ResEdit.
2. Open Future Extras.
3. Open the TlBx resource picker (shows all TlBx resources)
4. Open TlBx #129, "FN".
5. Select Find Hex from the Find menu.
6. Find Hex: 0506A9E40BFF and Change to: 0604A9E40B0CFF
Included here is additional information on the habits of LOCAL FNs hitherto unknown and undocumented.
A LOCAL FN is a self-contained program within the confines of a regular program. This allows the programmer to isolate routines from each other and avoid variable corruption.
When a LOCAL FN receives a parameter it makes a copy of the variable being passed thus ensuring that the original is never changed. When the routine exits via END FN or EXIT FN the local variable is removed from memory and no longer exists.
Multi-variable updating
There are three methods for updating multiple variables passed to a LOCAL FN. They include: globals, addresses, and records.
The first is the easiest but not the cleanest method of updating several variables wihtin a LOCAL FN. Define all the variables that need updating as global. You can then access them directly and change their values easily.
The second method requires that the address of the variable be passed to the LOCAL FN. The LOCAL FN makes changes by PEEKing and POKEing at the address. If you understand PEEK and POKE than this method works great.
The final method requires that you define a temporary record structure to pass the variables into the LOCAL FN (a paramblock) and then pass the record address to the function. You than access and update the record variables directly using normal record input and output methods. (ie. myRecPtr&.varOne% = 10). This method works well for those who don't think in PEEK and POKE terms.
Mysterious values
In certain circumstances you may find that a variable you thought you had defined locally in a LOCAL FN has mysteriously appeared in your main program.
This problem is easy to reproduce by defining a simple LOCAL FN that accepts a variable BUT DOESN'T return one. When used with the PRINT statement the value of the local variable 'q' is printed. Here is the example:
LOCAL FN Fred (tmp%)
q = 45
END FN
PRINT FN Fred (21)
Results in an output of:
45
Which is incorrect. Or is it?
The reason this situation occurs is simple. FB always uses Register D0 to return variables from any FN. The last variable assigned in the FN will always be found in D0. The END FN statement doesn't clear D0 when it executes thus leaving D0 holding the last variable bag. The PRINT statement simply prints what it finds in Register D0, the mysterious local variable left there by FN Fred.
If the END FN had contained a variable assignment, no anomoly would have occurred.